/*
 * NetRayt
 * Copyright (c) 2007-2008 Maciej Nabozny.
 *
 * NetRayt is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * NetRayt is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with NetRayt; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "client.h"
#include "serverThread.h"

/******************************************************************************/
/*                           Obsługa zakładki render                          */
/******************************************************************************/

/*
 * Uaktualnienie listy komputerów po zmianie zakładki na render
 * DODAĆ SORTOWANIE WG. WYBRANEGO KRYTERIUM
 */
void client::updateServers(int tab) {
	// sprawdź czy jest aktywna zakładka render
	if (tab != 2) {
		return;
	}
	
	qDebug("Dodaje serwery do listy...");
	QStandardItemModel sList(0, 1);
	sList.setHeaderData(0, Qt::Horizontal, tr("Serwery renderujące:"));
	
	// Wyczyść liste serwerów
	serverList.clear();
	
	// Odczytaj informacje o komputerach
	for (int i=0; i < servers->columnCount(); i++) {
		// tymczasowy obiekt przechowujacy dane o serwerze
		serverInfo inf;
		
		inf.host = servers->data(servers->index(0, i)).toString();
		inf.port = servers->data(servers->index(1, i)).toString().toInt();
		
		// Odczytanie inf. o wydajności komputerów
		inf.cpuf = servers->data(servers->index(2, i)).toInt();
		inf.cpuc = servers->data(servers->index(3, i)).toInt();
		inf.mem = servers->data(servers->index(4, i)).toInt();
		
		// Obsługa innych raytracerów:
		inf.yafray = servers->data(servers->index(5, i)).toBool();
		inf.blender = servers->data(servers->index(6, i)).toBool();
		inf.indigo = servers->data(servers->index(7, i)).toBool();
		
		inf.scenePart = 0;
		
		serverList.append(inf);
	}
	
	// podziel scene miedzy komputery
	divideScene();
	// pokaz komputery na liscie
	//showServers();
}

/*
 * Podział sceny wg. danych kryteriów
 * Wywoływane przez updateServers
 * Do zrobiebia sortowanie listy serwerów
 */
void client::divideScene() {
	if (serverList.size() == 0) {
		qDebug("Brak dostepnych serwerow");
		return;
	}
	
	// Zsumuj taktowania procesorów * ilośc procesorów
	// i rozmiar pamięci / ilość cpu
	int mem = 0;
	int cpuf = 0;
	
	for (int i = 0; i < serverList.size(); i++) {
		cpuf += serverList[i].cpuf * serverList[i].cpuc;
		mem += serverList[i].mem / serverList[i].cpuc;
	}
	
	// Określ obszary:
	for (int i = 0; i < serverList.size(); i++) {
		serverList[i].scenePart = ((double)serverList[i].cpuf * (double)serverList[i].cpuc) / (double)cpuf;
		
		qDebug(QString("Obszar: %1").arg(serverList[i].scenePart).toAscii());
	}
	
	// Posortuj serwery:
	// do zrobienia :]
	// od najmniejszego do najwiekszego!
	
	// Podziel scene między serwery:
	if (ui.detailsBorder->isChecked()) {
		qDebug("Rozklad sceny: najwiecej detali w centrum");
		int pos = 1;
		double lastPos_left = -1, lastPos_right = 1;
		for (int i = 0; i < serverList.size(); i++) {
			if (pos == 1) {
				serverList[i].x1 = lastPos_left;
				serverList[i].x2 = lastPos_left + (serverList[i].scenePart * 2);
				lastPos_left = lastPos_left + (serverList[i].scenePart * 2);
			} else if (pos == -1) {
				serverList[i].x2 = lastPos_right;
				serverList[i].x1 = lastPos_right - serverList[i].scenePart * 2;
				lastPos_right = lastPos_right - serverList[i].scenePart * 2;
			}
			pos *= -1;
			qDebug(QString("Host: %1:%2 (%3) - (%4)").arg(serverList[i].host).arg(serverList[i].port).arg(serverList[i].x1).arg(serverList[i].x2).toAscii());
		}
	} else if (ui.detailsCenter->isChecked()) {
		qDebug("Rozklad sceny: najwiecej detali a brzegach");
		int pos = 1;
		double lastPos_left = -1, lastPos_right = 1;
		for (int i = serverList.size()-1; i >= 0; i--) {
			if (pos == 1) {
				serverList[i].x1 = lastPos_left;
				serverList[i].x2 = lastPos_left + (serverList[i].scenePart * 2);
				lastPos_left = lastPos_left + (serverList[i].scenePart * 2);
			} else if (pos == -1) {
				serverList[i].x2 = lastPos_right;
				serverList[i].x1 = lastPos_right - serverList[i].scenePart * 2;
				lastPos_right = lastPos_right - serverList[i].scenePart * 2;
			}
			
			// Zmien miejsce nastepnego ffranmentu (żeby było po drugiej stronie)
			pos *= -1;
			qDebug(QString("Host: %1:%2 (%3) - (%4)").arg(serverList[i].host).arg(serverList[i].port).arg(serverList[i].x1).arg(serverList[i].x2).toAscii());
		}
	}
}

/*
 * Rozpoczecie raytracingu
 */
void client::startRender() {
	serverThreadList = new serverThread[serverList.size()];
	
	for (int i = 0; i < serverList.size(); i++) {
		qDebug(QString("client::startRender: Przygotowanie danych dla %1").arg(serverList[i].host).toAscii());
		serverThreadList[i].info = serverList[i];
		serverThreadList[i].scene = scene;
		serverThreadList[i].run();
		
		connect(&serverThreadList[i], SIGNAL(ready()), this, SLOT(ready()));
	}
	qDebug("client::startRender: Wysylanie danych do serwerow...");
}

/*
 * Sprawdzenie czy wszystkie serwery zakonczyly raytracing
 * Wywoływane po zakończeniu każdego serverThread
 */
void client::ready() {
	// sprawdź czy wszystkie procesy się zakończyły
	bool all_done = 1;
	for (int i = 0; i < serverList.size(); i++) {
		if (serverThreadList[i].done == 0) {
			all_done = 0;
			break;
		}
	}
	
	// Jeżeli wszystkie procesy sie zakończyły, to zacznij składać obrazek
	if (all_done) {
		for (int i = 0; i < serverList.size(); i++) {
			qDebug(QString("client::ready: Obrazek %1").arg(serverThreadList[i].image).toAscii());
		}
		createImage();
	}
}

/*
 * Połącz obrazki ze wszystkich serwerów w jeden
 */
void client::createImage() {
	if (serverList.size() == 0) {
		qDebug("client::createImage: Pusta lista serwerów!");
	}
	
	// Otwórz pierwszy obrazek. Na niego będą nakładane następne fragmenty z innych obrazków
	QImage img(serverThreadList[0].image);
	int width = img.width();
	int height = img.height();
	
	// Dodaj następne obrazki
	for (int i = 1; i < serverList.size(); i++) {
		QImage temp(serverThreadList[i].image);
		int x1, x2, y1, y2;
		
		// Odczytaj wspolrzedne fragmentu
		if (serverThreadList[i].info.vertical) {
			y1 = 0;
			y2 = height;
			
			x1 = width * (-1 + serverThreadList[i].info.x1);
			x2 = width * (-1 + serverThreadList[i].info.x2);
		}
		
		// Przekopiuj obszar:
		for (int i = x1; i < x2; i++) {
			for (int j = y1; j < y2; j++) {
				img.setPixel(i, j, temp.pixel(i, j));
			}
		}
		
		// Zapisz
		img.save("/tmp/out.png");
	}
}

void client::endApp() {
	this->close();
}
